package com.cn.lp.jpa.cq.test.domain;

/**
 * 多次数任务
 */
public abstract class AbstractMultiTimesScheduleTask<TTrigger extends TaskTrigger> extends ScheduleTask<TTrigger> {

    public AbstractMultiTimesScheduleTask(String name, TTrigger trigger) {
        super(name, trigger);
    }

    @Override
    protected final void doExec() {
        Long startTime = getNextTriggerTime();
        int runTimes = 0;
        Long executeTime;
        Long nextTime = startTime;
        do {
            if (this.isExecEveryTimes()) {
                executeTime = getNextTriggerTime();
                execOnce(startTime, runTimes, executeTime);
                nextTime = getNextTriggerTime();
            } else {
                runTimes = runTimes + 1;
                executeTime = nextTime;
                nextTime = getNextTriggerTime(executeTime);
            }
        } while (nextTime != null && System.currentTimeMillis() >= nextTime);
        if (!this.isExecEveryTimes()) {
            execOnce(startTime, runTimes - 1, executeTime);
        }
    }

    private void execOnce(long startTime, int runTimes, long executeTime) {
        preExecOnce(startTime, runTimes, executeTime);
        try {
            doExecOnce(startTime, runTimes, executeTime);
        } finally {
            triggerNextTime(executeTime);
        }
        postExecOnce(startTime, runTimes, executeTime);
    }

    public abstract boolean isExecEveryTimes();

    protected void preExecOnce(long startTime, int runTimes, long executeTime) {
    }

    protected void postExecOnce(long startTime, int runTimes, long executeTime) {
    }

    protected abstract void doExecOnce(long startTime, int runTimes, long executeTime);

    private Long getNextTriggerTime() {
        return getTrigger().getNextTriggerTime().orElse(null);
    }

    private Long getNextTriggerTime(long currentTime) {
        return getTrigger().getTriggerTimeAfter(currentTime).orElse(null);
    }

}
